﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using OffInvoiceExcelAddIn.UBLFiles;
using OffInvoiceExcelAddIn.CIIFiles;
using System.IO;
using System.Windows.Forms;
using OffInvoiceExcelAddIn.FacturaeFiles;
using Microsoft.Office.Interop.Excel;

namespace OffInvoiceExcelAddIn
{
    /// <summary>
    /// Clase que controla la importación de los datos de una factura.
    /// </summary>
    class ImportInvoiceController
    {
        #region "Fields"

        /// <summary>
        /// Campo con el documento XML que se va a importar
        /// </summary>
        private XmlDocument doc = null;

        /// <summary>
        /// Campo que indica si la factura es en papel o electrónica
        /// </summary>
        private bool papel = true;

        /// <summary>
        /// Campo con el path donde se encuentra la factura
        /// </summary>
        private string filePath = string.Empty;


        #endregion

        #region "Constructors"

        /// <summary>
        /// Contructor que inicia la importación
        /// </summary>
        /// <param name="filePath">Path de la factura</param>
        public ImportInvoiceController(string filePath)
        {
            this.filePath = filePath;
            this.doc = new XmlDocument();
            doc.PreserveWhitespace = true;
            try
            {
                doc.Load(filePath);
            }
            catch (Exception)
            {

                throw new Exception(ControlMessages.Msg.XmlMalformed.ToString("g"));
            }
            if (doc.DocumentElement.NamespaceURI.Equals("urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"))
            {
                importUBL();
            }
            else if (doc.DocumentElement.NamespaceURI.Equals("urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:1"))
            {
                importCII();
            }
            else
            {
                importFacturae();

            }

            ////DESPUES DE IMPORTAR LA FACTURA, SE DEBE BLOQUEAR PARA IMPEDIR SU EDICION

            //Globals.ThisAddIn.lockDocument(true);
        }

        #endregion

        #region "Privated Methods"

        /// <summary>
        /// Método que se encarga de la importación de una factura en formato UBL, además de realizar la validación
        /// a 3 niveles para mostrar los resultados al usuario si lo desea
        /// </summary>
        private void importUBL()
        {
            XmlDocument docSinFirma = new XmlDocument();
            docSinFirma.PreserveWhitespace = true;
            docSinFirma.LoadXml(doc.OuterXml);

            XmlNode signatureNode = docSinFirma.DocumentElement.GetElementsByTagName("Signature").Item(0);
            if (signatureNode != null)
            {
                docSinFirma.DocumentElement.GetElementsByTagName("Signature", "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2").Item(0).RemoveChild(signatureNode);
            }
            ResultUBLValidation schemaV = UBLValidation.SchemaValidation(docSinFirma);
            ResultUBLValidation accountV = UBLValidation.AccountValidation(doc);
            ResultUBLValidation signedV = UBLValidation.SignedValidation(doc);
            LoadController load = new LoadController();
            load.LoadUBL(filePath, true, false, true);
            //loadBlockDocument();
            string data = doc.OuterXml;
            if (data.IndexOf("Signature") > 0)
            {
                papel = false;
                Globals.ThisAddIn.AddCustomXmlPart(data, Globals.ThisAddIn.Application.ActiveWorkbook);
            }
            if (showMessages(schemaV.Success, accountV.Success, signedV.Success, ControlMessages.Msg.MsgInfoSchemaUBL.ToString("g")))
            {
                ValidateController v = new ValidateController();
                v.validateUBL(doc, false);
            }
        }

        /// <summary>
        /// Método que se encarga de la importación de una factura en formato Facturae, además de realizar la validación
        /// a 3 niveles para mostrar los resultados al usuario si lo desea
        /// </summary>
        private void importFacturae()
        {
            bool schema = true;
            bool account = true;
            bool signed = true;

            try
            {
                LoadController load = new LoadController();
                load.LoadFacturae(filePath, false, true, true);
            }
            catch (Exception)
            {
                schema = false;
                throw new Exception("1");
            }
            ValidateController v = new ValidateController();
            try
            {
                if (doc.DocumentElement.NamespaceURI.Equals("http://www.facturae.es/Facturae/2007/v3.1/Facturae"))
                {
                    v.AccountingValidation(filePath, true, InvoiceTypes.FACTURAE_3_1);
                }
                else if (doc.DocumentElement.NamespaceURI.Equals("http://www.facturae.es/Facturae/2009/v3.2/Facturae"))
                {
                    v.AccountingValidation(filePath, true, InvoiceTypes.FACTURAE_3_2);
                }

            }
            catch (Exception)
            {
                account = false;
            }

            try
            {
                v.SignatureValidations(filePath);
            }
            catch (Exception)
            {
                signed = false;
            }
            //loadBlockDocument();
            string data = doc.OuterXml;
            if (data.IndexOf("Signature") > 0)
            {
                papel = false;
                Globals.ThisAddIn.AddCustomXmlPart(data, Globals.ThisAddIn.Application.ActiveWorkbook);
            }
            if (showMessages(schema, account, signed, ControlMessages.Msg.MsgInfoSchemaFacturae31.ToString("g")))
            {
                if (papel)
                {
                    if (doc.DocumentElement.NamespaceURI.Equals("http://www.facturae.es/Facturae/2007/v3.1/Facturae"))
                    {
                        v.validatePaper(InvoiceTypes.FACTURAE_3_1, false);
                    }
                    else if (doc.DocumentElement.NamespaceURI.Equals("http://www.facturae.es/Facturae/2009/v3.2/Facturae"))
                    {
                        v.validatePaper(InvoiceTypes.FACTURAE_3_2, false);
                    }

                }
                else
                {
                    v.validateFacturae(doc, false);
                }
            }
        }


        /// <summary>
        /// Método que se encarga de la importación de una factura en formato CII, además de realizar la validación
        /// a 3 niveles para mostrar los resultados al usuario si lo desea
        /// </summary>
        private void importCII()
        {
            XmlDocument docSinFirma = new XmlDocument();
            docSinFirma.PreserveWhitespace = true;
            docSinFirma.LoadXml(doc.OuterXml);

            XmlNode signatureNode = docSinFirma.DocumentElement.GetElementsByTagName("Signature").Item(0);
            if (signatureNode == null)
                signatureNode = docSinFirma.DocumentElement.GetElementsByTagName("ds:Signature").Item(0);
            if (signatureNode != null)
            {
                docSinFirma.DocumentElement.RemoveChild(signatureNode);
            }
            ResultCIIValidation schemaV = CIIValidation.SchemaValidation(docSinFirma);
            ResultCIIValidation accountV = CIIValidation.AccountValidation(doc);
            ResultCIIValidation signedV = CIIValidation.SignedValidation(doc);
            LoadController load = new LoadController();
            load.LoadCII(filePath, true, false, true);
            //loadBlockDocument();
            string data = doc.OuterXml;
            if (data.IndexOf("Signature") > 0)
            {
                papel = false;
                Globals.ThisAddIn.AddCustomXmlPart(data, Globals.ThisAddIn.Application.ActiveWorkbook);
            }
            if (showMessages(schemaV.Success, accountV.Success, signedV.Success, ControlMessages.Msg.MsgInfoSchemaCII.ToString("g")))
            {
                ValidateController v = new ValidateController();
                v.validateCII(doc, false);
            }
        }

        /// <summary>
        /// Método que se encarga de bloquear los campos de la factura para evitar modificaciones ilegales
        /// </summary>
        private void loadBlockDocument()
        {
            try
            {
                string tempDir = Path.GetTempPath();

                string data = doc.OuterXml;
                if (data.IndexOf("Signature") > 0)
                {
                    papel = false;
                    Globals.ThisAddIn.AddCustomXmlPart(data, Globals.ThisAddIn.Application.ActiveWorkbook);
                }

                string name = "";

                try
                {
                    name = string.Concat(Globals.ThisAddIn.GetControlValue(ControlList.Tag.SP_TaxIdentificationNumber), Globals.ThisAddIn.GetControlValue(ControlList.Tag.IH_InvoiceNumber), Globals.ThisAddIn.GetControlValue(ControlList.Tag.IH_InvoiceSeriesCode));
                }
                catch (Exception) { }

                object filename;

                if (string.IsNullOrEmpty(name))
                    filename = Path.GetTempFileName();
                else
                    filename = tempDir + name;

                object missing = System.Reflection.Missing.Value;
                if (File.Exists(((String)filename) + ".xlsx"))
                {
                    File.Delete(((String)filename) + ".xlsx");
                }
                Globals.ThisAddIn.Application.ActiveWorkbook.SaveAs(filename, missing, missing, missing, missing, missing, XlSaveAsAccessMode.xlShared, missing, missing, missing, missing, missing);

            }
            catch (Exception) { }

        }

        /// <summary>
        /// Método que muestra un mensaje informativo después de realizar la importación de una factura.
        /// </summary>
        /// <param name="schema">Resultado de la validación del esquema de la factura</param>
        /// <param name="account">Resultado de la validación contable de la factura</param>
        /// <param name="signed">Resultado de la validación de firma de la factura</param>
        /// <param name="msgInfoSchema">Mensaje informativo par mostrar</param>
        /// <returns>True o False si el usuario desea ver los datos de validación</returns>
        private bool showMessages(bool schema, bool account, bool signed, string msgInfoSchema)
        {
            ControlMessages msg = ControlMessages.getInstance();
            if (!schema || !account || (!signed && !papel))
            {
                string error = msg.getMessage(ControlMessages.Msg.ErrorSchema) + " " + msg.getMessage(ControlMessages.Msg.ErrorFails) + "\n";
                if (!schema)
                    error += "  " + msg.getMessage(msgInfoSchema) + "\n";
                if (!account)
                    error += "  " + msg.getMessage(ControlMessages.Msg.MsgAccounValidation) + "\n";
                if (!signed)
                    error += "  " + msg.getMessage(ControlMessages.Msg.MsgSing) + "\n";
                error += msg.getMessage(ControlMessages.Msg.MsgInfoViewDetails);
                if (MessageBox.Show(error, msg.getMessage(ControlMessages.Msg.CaptionFacturae), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    return true;
                }
            }
            else
            {
                if (MessageBox.Show(msg.getMessage(ControlMessages.Msg.InfoImportOK), msg.getMessage(ControlMessages.Msg.CaptionFacturae), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    return true;
                }
            }
            return false;
        }

        #endregion

    }
}
